package com.mgq.algorithm.dabiaofa;

/**
 * 给定一个函数f，可以1~5的数字等概率返回一个。请加工出1~7的数字等概率
 * 返回一个的函数g。
 * 给定一个函数f，可以a~b的数字等概率返回一个。请加工出c~d的数字等概率
 * 返回一个的函数g。
 * 给定一个函数f，以p概率返回0,以1-p概率返回1。请加工出等概率返回0和1的
 * 函数g
 */
public class Rand5To7 {

    public static int f() {
        return (int) ((Math.random() * 5) + 1);
    }

    /**
     * 这种题首先应该想到二进制拼接.应该想办法等概率生成0和1
     * @return
     */
    public static int rc1() {
        int res=0;
        do {
            res = f();
        } while (res==3);
        return res < 3 ? 0 : 1;
    }

    /**
     * 一个二进制 可以等概率返回 0和1
     * 两个二进制 可以等概率返回 0和3
     * 三个二进制 可以等概率返回 0和7
     * @return
     */
    public static int g() {
        int res=0;
        do {
            res = (rc1() << 2) + (rc1() << 1) + rc1();
        } while (res == 7);
        return res + 1;
    }

    /**
     *  给定一个函数f，可以a~b的数字等概率返回一个。请加工出c~d的数字等概率返回一个的函数g。
     *  比如 给个 10-15等概率返回的函数f(). 要求等概率返回30-60;
     *  解题思路: 1. 首先生成 0,1 发生器 (等概率)
     *          2. 看几个二进制位够用
     *          3. 生成0 - 位数的函数(等概率) 超过位数的部分重新做
     *          4.返回 0 + x ,就表示 c-d等概率的数
     * @return
     */
    public static int g1() {
        int res=0;
        //2的5次方 32
        do {
            res=(rc2()<<4)+(rc2()<<3)+(rc2()<<2)+(rc2()<<1)+rc2();
        }while (res==31);
        return res+30;
    }

    public static int rc2() {
        return f2() < 13 ? 1 : 0;
    }
    /**
     * 随机生成10-15
     * @return
     */
    public static int f2() {
        return (int) ((Math.random() * 5) + 11);
    }
    public static void main(String[] args) {
        int count=0;
        for (int i = 0; i < 1000000; i++) {
            //int g = g1();
            int g = g3();
            //System.out.println(g);
            if (g == 1) {
                count++;
            } else {
                count--;
            }

          /*  if (g < 30 || g > 60) {
                System.out.println(g);
                System.out.println("error");
            }*/
        }
        System.out.println(count);
    }

    /**
     * 给定一个函数f，以p概率返回0,以1-p概率返回1。请加工出等概率返回0和1的g函数
     * 解决方法. 抛两次
     * 如果是00,11 重抛
     * 如果是 01 概率是 p*(1-p) 表示0
     * 如果是 10 概率是(1-p)*p  表示1
     * 最终生成的数就是等概率的0和1
     * @return
     */
    public static int g3() {
        int res = -1;
        do {
            res = (rc1()<<1) + rc1();
        } while (res == 0 || res == 3);
        return res==2?1:0;
    }
}
